//// InventoryFileSystem.cs
////	
//// Author:
////   [NAME] [EMAIL]
////
//// Copyright (c) 2008, [OWNER]
////
//// All rights reserved.
////
//// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
////
////    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
////    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
////    * Neither the name of the [ORGANIZATION] nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
////
//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
////
////
//
//using System;
//using System.Threading;
//using System.Diagnostics;
//using System.Collections.Generic;
//using OpenMetaverse;
//using log4net;
//using log4net.Config;
//
//using Mono.Unix.Native;
//
//namespace OpenFuse.FileSystem
//{
//	public class Fuse : Mono.Fuse.FileSystem
//	{
//		private static readonly ILog _logger = LogManager.GetLogger("FileSystem");
//
//		Dictionary<int, Cache.Asset> _handles;
//		static int _handleCount = 0;
//		Cache.LocalCache _cache;
//				
//		
//		protected override Errno OnReadDirectory(string directory, Mono.Fuse.OpenedPathInfo info, out IEnumerable<Mono.Fuse.DirectoryEntry> names)
//		{
//			_logger.Debug("OnReadDirectory " + directory);
//			
//			names = null;
//			List<Mono.Fuse.DirectoryEntry> children = new List<Mono.Fuse.DirectoryEntry>();
//			
//			if(directory == "/")		// root
//			{
//				foreach(Cache.Grid g in _cache.Grids.GetActiveGrids()) 
//				{
//					Mono.Fuse.DirectoryEntry de = new Mono.Fuse.DirectoryEntry(g.Nick);
//					de.Stat.st_gid = (uint)GetOperationContext().GroupId;
//					de.Stat.st_uid = (uint)GetOperationContext().UserId;
//					de.Stat.st_nlink = 1;
//					de.Stat.st_mode = NativeConvert.FromUnixPermissionString("drw-rw-r--");
//					children.Add(de);
//				}
//			}
//			else if(directory.LastIndexOf("/") == 0)	// grid
//			{
//				Comms.IGrid g = _cache.Grids.GetByNick(directory.Substring(1));
//				if(g != null)
//				{
//					foreach(Comms.IAccount a in _cache.Accounts.GetByNick(g.Nick))
//					{
//						Mono.Fuse.DirectoryEntry de = new Mono.Fuse.DirectoryEntry(a.FirstName +"."+ a.LastName);
//						de.Stat.st_gid = (uint)GetOperationContext().GroupId;
//						de.Stat.st_uid = (uint)GetOperationContext().UserId;
//						de.Stat.st_nlink = 1;
//						de.Stat.st_mode = NativeConvert.FromUnixPermissionString("drw-rw-r--");
//						children.Add(de);
//					}
//				}
//			}
//			else
//			{
//				// get the node
//				Cache.Node baseNode = _cache.Nodes.GetByPath(directory);
//				
//				// is the folder empty?
//				if(baseNode == null)
//				{
//					names = children;
//					return 0;
//				}
//				
//				if(baseNode.GetType() != typeof(Cache.FolderNode))		// it *must* be a folder
//					return Errno.ENOTDIR;
//				
//				// safe to cast now that we've checked
//				Cache.FolderNode baseFolder = (Cache.FolderNode)baseNode;
//				
//				try{
//					foreach(Cache.Node n in baseFolder.Children)
//					{
//						if(n is Cache.FolderNode)
//						{
//							Mono.Fuse.DirectoryEntry de = new Mono.Fuse.DirectoryEntry(n.Name);
//							de.Stat.st_gid = (uint)GetOperationContext().GroupId;
//							de.Stat.st_uid = (uint)GetOperationContext().UserId;
//							de.Stat.st_nlink = 1;
//							de.Stat.st_mode = NativeConvert.FromUnixPermissionString("drw-rw-r--");
//							de.Stat.st_ino = (ulong)n.RowId;
//							children.Add(de);
//						} else if(n is Cache.FileNode) {
//							Mono.Fuse.DirectoryEntry de = new Mono.Fuse.DirectoryEntry(n.Name);
//							de.Stat.st_gid = (uint)GetOperationContext().GroupId;
//							de.Stat.st_uid = (uint)GetOperationContext().UserId;
//							de.Stat.st_nlink = 1;
//							de.Stat.st_mode = NativeConvert.FromUnixPermissionString("-rw-rw-r--");
//							de.Stat.st_ino = (ulong)n.RowId;
//							children.Add(de);
//						}
//					}
//				} catch(Exception e) {
//					Console.WriteLine(e);
//				}
//			}			
//			names = children;
//			_logger.Debug("OnReadDirectory - exit");
//			return 0;
//		}
//
//		protected override Errno OnGetPathStatus(string path, out Stat stbuf)
//		{
//			_logger.Debug("OnGetPathStatus " + path);
//			Errno result = Errno.ENOENT;
//
//			stbuf = new Stat();
//			if(path == "/")
//			{
//					stbuf.st_mode  = NativeConvert.FromUnixPermissionString("dr-xr-xr-x");
//					result = 0;
//			}
//			else if(path.LastIndexOf("/") == 0)
//			{
//				Comms.IGrid g = _cache.Grids.GetByNick(path.Substring(1));
//				if(g != null)
//				{
//					stbuf.st_mode  = NativeConvert.FromUnixPermissionString("dr-xr-xr-x");
//					result = 0;
//				}
//				// if not found, go for the default ENOENT error code
//			}
//			else
//			{
//				try
//				{
//					Cache.Node node = _cache.Nodes.GetByPath(path);
//					if(node != null)
//					{
//						if(node is Cache.FolderNode)
//						{
//							stbuf.st_mode  = NativeConvert.FromUnixPermissionString("dr-xr-xr-x");
//							result = 0;
//						}
//						else if(node is Cache.FileNode)
//						{
//							stbuf.st_mode  = NativeConvert.FromUnixPermissionString("-rw-rw-r--");
//							stbuf.st_ctime = (long)((DateTime.Now - new DateTime(1970,1,1,0,0,0)).TotalSeconds);
//							stbuf.st_atime = stbuf.st_ctime;
//							stbuf.st_mtime = stbuf.st_ctime;
//							stbuf.st_size = _cache.Assets.GetByNodeId(node.Id).Size;
//							result = 0;
//						} else
//							result = Errno.ENOENT;
//						
//						stbuf.st_nlink = 1;
//						stbuf.st_uid = (uint)GetOperationContext().UserId;
//						stbuf.st_gid = (uint)GetOperationContext().GroupId;
//					} else {
//						
//						// maybe we know the account and the grid, but nothing has been
//						// replicated yet.
//						string[] pathElements = path.Split('/');
//						if(pathElements.Length == 3)
//						{
//							foreach(Comms.IAccount a in _cache.Accounts.GetByNick(pathElements[1]))
//							{
//								if(a.FirstName +"."+ a.LastName == pathElements[2])
//								{
//									stbuf.st_mode  = NativeConvert.FromUnixPermissionString("dr-xr-xr-x");
//									result = 0;
//									break;
//								}
//							}
//						}
//						else // TODO FileNodes doesn't have a path entry, this really should be fixed in the replication engine
//						{
//							string directory = System.IO.Path.GetDirectoryName(path);
//							
//							node = _cache.Nodes.GetByPath(directory);
//							if(node is Cache.FolderNode)
//							{
//								stbuf.st_mode  = NativeConvert.FromUnixPermissionString("dr-xr-xr-x");
//								result = 0;
//							}
//							else if(node is Cache.FileNode)
//							{
//								stbuf.st_mode  = NativeConvert.FromUnixPermissionString("-rw-rw-r--");
//								stbuf.st_ctime = (long)((DateTime.Now - new DateTime(1970,1,1,0,0,0)).TotalSeconds);
//								stbuf.st_atime = stbuf.st_ctime;
//								stbuf.st_mtime = stbuf.st_ctime;
//								Cache.Asset asset = _cache.Assets.GetByNodeId(node.Id);
//								if(asset != null)
//									stbuf.st_size = asset.Size;
//								else
//									stbuf.st_size = 0;
//								
//								result = 0;
//							} else {
//								result = Errno.ENOENT;
//							}
//							
//						}
//					}
//				}
//				catch(Exception e)
//				{
//					_logger.Error("OnGetPathStatus error ", e);
//				}
//			}
//			_logger.Debug("OnGetPathStatus - exit");
//			return result;
//		}
//
//		protected override Errno OnGetFileSystemStatus(string path, out Statvfs buffer)
//		{
//			_logger.Debug("OnGetFileSystemStatus " + path);
//			buffer = new Statvfs();
////			buffer.f_flag = MountFlags.ST_NODEV|MountFlags.ST_NOATIME|MountFlags.ST_NODIRATIME;
//			buffer.f_flag = MountFlags.ST_NOATIME|MountFlags.ST_NODIRATIME;
//			buffer.f_namemax = 64;
//			return 0;
//		}
//
//		protected override Errno OnGetPathExtendedAttribute(string path, string name, byte[] value, out int bytesWritten)
//		{
//			_logger.Info("OnGetPathExtendedAttribute " + path+":"+name);
//			bytesWritten = 0;
//			return 0;
//		}
//
//		protected override Errno OnSetPathExtendedAttribute(string path, string name, byte[] value, XattrFlags flags)
//		{
//			_logger.Info("OnSetPathExtendedAttribute " + path+":"+name);
//			return Errno.EOPNOTSUPP;
//		}
//			
//		protected override Errno OnListPathExtendedAttributes(string path, out string[] names)
//		{
//			_logger.Info("OnListPathExtendedAttributes " + path);
//			names = null;
//			return Errno.EOPNOTSUPP;
//		}
//
//		protected override Errno OnRemovePathExtendedAttribute (string path, string name)
//		{
//			_logger.Info("OnRemovePathExtendedAttribute " + path+":"+name);
//			return Errno.EOPNOTSUPP;
//		}
//			
//		protected override Errno OnOpenHandle(string file, Mono.Fuse.OpenedPathInfo info)
//		{
//			_logger.Debug("OnOpenHandle " + file);
//			Errno result = 0;
//			try
//			{
//				Cache.Node n = _cache.Nodes.GetByPath(file);
//				if(n == null)
//					return Errno.ENOENT;
//	
//				if( (info.OpenAccess & (OpenFlags.O_RDWR|OpenFlags.O_WRONLY)) != OpenFlags.O_RDONLY)  	
//					return Errno.EACCES;
//
//
//				if(n is Cache.FileNode)
//				{
//					int handle = Interlocked.Increment(ref _handleCount);
//					_handles.Add(handle, _cache.Assets.GetByNodeId(n.Id));
//					info.Handle = (IntPtr)handle;
//					result = 0;
//				}
//				else
//					result = Errno.EISDIR;
//			}
//			catch(Exception e)
//			{
//				_logger.Error(e);
//			}
//			return result;
//		}
//
//		protected override Errno OnReadHandle(string file, Mono.Fuse.OpenedPathInfo info, byte[] buf, long offset, out int bytesWritten)
//		{
//			_logger.Debug("OnReadHandle " + file);
//			Cache.Asset a = _handles[(int)info.Handle];
//			byte[] data = a.Data;
//
//			if(offset+buf.Length>data.Length)
//				bytesWritten = (int)(data.Length - offset);
//			else
//				bytesWritten = buf.Length;
//			
//			Buffer.BlockCopy(data, (int)offset, buf, 0, bytesWritten);
//			return 0;
//		}
//
//		protected override Errno OnGetHandleStatus(string file, Mono.Fuse.OpenedPathInfo info, out Stat buf)
//		{
//			_logger.Debug("OnGetHandleStatus " + file);
//			buf = new Stat();
//			if(_handles.ContainsKey((int)info.Handle))
//			{
//				Cache.Asset a = _handles[(int)info.Handle];
//
//				buf.st_mode  = NativeConvert.FromUnixPermissionString("-rw-rw-r--");
////				buf.st_ctime = (long)(f.Creationtime - new DateTime(1970,1,1,0,0,0)).TotalSeconds;
//				buf.st_atime = buf.st_ctime;
//				buf.st_mtime = buf.st_ctime;
//				buf.st_size  = a.Data.Length;
//				buf.st_nlink = 1;
//			}
//			else
//				return Errno.ENOENT;
//			return 0;
//		}
//		
//		protected override Errno OnReleaseHandle(string file, Mono.Fuse.OpenedPathInfo info)
//		{
//			_logger.Debug("OnReleaseHandle " + file);
//			if(_handles.ContainsKey((int)info.Handle))
//				_handles.Remove((int)info.Handle);
//			else
//				return Errno.ENOENT;
//			
//			return 0;
//		}
//		
//		public Fuse(string mountPoint, Cache.LocalCache cache) : base(mountPoint)
//		{
//			_logger.Debug("FileSystem ctor");
//			DefaultUserId = Mono.Unix.UnixUserInfo.GetRealUser().UserId;
//			DefaultGroupId = Mono.Unix.UnixUserInfo.GetRealUser().GroupId;
////			EnableFuseDebugOutput = true;
//			MultiThreaded = false;
//
//			Name = "OpenFuse";
//			_cache = cache;
//			_handles = new Dictionary<int, Cache.Asset>();
//		}
//	}
//}
//
